package com.yawn.spock

import com.yawn.spock.service.CalculateInterface
import com.yawn.spock.service.CalculateService
import spock.lang.Specification


/**
 * <pre>
 *
 * Stub与Mock
 * （1）相同点
 *      Stub和Mock对象都是用来模拟外部依赖，使我们能控制。
 *      如果被测程序、系统或对象，我们称之为A。在测试A的过程中，
 *      A需要与程序、系统或对象B进行交互，那么Stub/Mock就是用来模拟B的行为来与A进行交互。
 * （2）不同点
 *      Stub，也即“桩”，很早就有这个说法了，主要出现在集成测试的过程中，
 *      从上往下的集成时，作为下方程序的替代。作用如其名，就是在需要时，
 *      能够发现它存在，即可。就好像点名，“到”即可。
 *      Mock，主要是指某个程序的傀儡，也即一个虚假的程序，
 *      可以按照测试者的意愿做出响应，返回被测对象需要得到的信息。
 *      也即是要风得风、要雨得雨、要返回什么值就返回什么值。
 *
 *      总体来说，stub完全是模拟一个外部依赖，用来提供测试时所需要的测试数据。
 *      而mock对象用来判断测试是否能通过，也就是用来验证测试中依赖对象间的交互能否达到预期。
 * </pre>
 * @author yawn
 *     2019/6/10 14:52
 */
class StubSpec extends Specification {

    def "stub 测试桩"() {
        given: "构造测试桩"
        CalculateInterface calculateService = Stub(CalculateInterface)
        // 强制指定被调用方法的返回值为1
        calculateService.plusPlus(_) >> 1

//        calculateService.plusPlus(_) >>> [1, 2, 3] >> { throw new InternalError() } >> 0

        when:
        int x = calculateService.plusPlus(12)
        int y = calculateService.plusPlus(3)

        then:
        x == 1
        y == 1
    }


    def "stub 测试桩得到不同的多个值"() {
        given: "构造测试桩"
        CalculateService calculateService = Stub(CalculateService)
        // 强制指定被调用方法的返回值为 [1, 2, 3]
        calculateService.plusPlus(_) >>> [1, 2, 3]

        when:
        int x = calculateService.plusPlus(12)
        int y = calculateService.plusPlus(3)
        int z = calculateService.plusPlus(2)

        then:
        x == 1
        y == 2
        z == 3
    }

}

